home *** CD-ROM | disk | FTP | other *** search
/ Die Ultimative Software-P…i Collection 1996 & 1997 / Die Ultimative Software-Pakete CD-ROM fur Atari Collection 1996 & 1997.iso / a / a_funk / geograph.tos / GEOGRAPH / SUNCLOCK / SUNCLOCK.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-06  |  21.0 KB  |  791 lines

  1. /*
  2.     ATARI-ST clock    by Joep Mathijssen
  3.  
  4.     Original header:
  5.     ---------------
  6.  
  7.     Sun clock
  8.  
  9.     Designed and implemented by John Walker in November of 1988.
  10.  
  11.     Version for the Sun Workstation.
  12.  
  13.     The algorithm used to calculate the position of the Sun is given in
  14.     Chapter 18 of:
  15.  
  16.     "Astronomical  Formulae for Calculators" by Jean Meeus, Third Edition,
  17.     Richmond: Willmann-Bell, 1985.  This book can be obtained from:
  18.  
  19.        Willmann-Bell
  20.        P.O. Box 35025
  21.        Richmond, VA  23235
  22.        USA
  23.        Phone: (804) 320-7016
  24.  
  25.     This program was written by:
  26.  
  27.        John Walker
  28.        Autodesk, Inc.
  29.        2320 Marinship Way
  30.        Sausalito, CA  94965
  31.        USA
  32.        Fax:   (415) 389-9418
  33.        Voice: (415) 332-2344 Ext. 2829
  34.        Usenet: {sun,well,uunet}!acad!kelvin
  35.        or: kelvin@acad.uu.net
  36.  
  37.     This  program is in the public domain: "Do what thou wilt shall be the
  38.     whole of the law".  I'd appreciate  receiving  any  bug  fixes  and/or
  39.     enhancements,  which  I'll  incorporate  in  future  versions  of  the
  40.     program.  Please leave the original attribution information intact    so
  41.     that credit and blame may be properly apportioned.
  42.  
  43.     Revision history:
  44.  
  45.     1.0  12/21/89  Initial version.
  46.           8/24/89  Finally got around to submitting.
  47.  
  48. */
  49.  
  50. #include <stdio.h>
  51. #include <stdlib.h>
  52. #include <ctype.h>
  53. #include <string.h>
  54. #include <math.h>
  55. #include <time.h>
  56. #include <assert.h>
  57. #include <tos.h>
  58. #include <vdi.h>
  59. #include <aes.h>
  60.  
  61. #include "gem.h"
  62. #include "dialog.h"
  63. #include "scr2.h"
  64. #include "sunclock.img"              /* Icon and open window bitmaps */
  65. #include "sunclock.h"                            /* .RCS-file */
  66.  
  67. /*----- Prototypes -----*/
  68. void pw_setmode( int );
  69. void pw_vector( void*, int, int, int, int, int, int );
  70. void pw_b_on( void* );
  71. void pw_b_off( void* );
  72. void updimage( int );
  73. void timer_proc( void );
  74. static void   cevent( void );
  75. static long   jdate( struct tm* );
  76. static double jtime( struct tm* );
  77. static double kepler( double, double );
  78. static void   sunpos( double, int, double*, double*, double*, double* );
  79. static double gmst( double );
  80. static void projillum( short*, int, int, double );
  81. static void xspan( int, int, int );
  82. static void moveterm( short*, int, short*, int, int, int );
  83.  
  84. OBJECT  *dialog_addr;
  85. bool    bufferio;
  86.  
  87. #define abs(x) ((x) < 0 ? (-(x)) : x)              /* Absolute value */
  88. #define sgn(x) (((x) < 0) ? -1 : ((x) > 0 ? 1 : 0))      /* Extract sign */
  89. #define dtr(x) ((x) * (PI / 180.0))              /* Degree->Radian */
  90. #define rtd(x) ((x) / (PI / 180.0))              /* Radian->Degree */
  91. #define fixangle(a) ((a) - 360.0 * (floor((a) / 360.0)))  /* Fix angle      */
  92.  
  93. #define V      (void)
  94.  
  95. #define PI 3.14159265358979323846
  96.  
  97. #define TERMINC  100           /* Circle segments for terminator */
  98.  
  99. #define PROJINT  (60 * 10)       /* Frequency of seasonal recalculation
  100.                       in seconds. */
  101.  
  102. #define OXDOTS     640           /* Open window width */
  103. #define OYDOTS     320          /* Open window height */
  104.  
  105. /*  Globals imported  */
  106.  
  107. extern time_t time();
  108.  
  109. /*  Local variables  */
  110.  
  111. static int xdots, ydots;       /* Screen size */
  112.  
  113. static char *wdname[] = {       /* Week day names */
  114.         "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  115. };
  116.  
  117. static int onoon = -1;
  118. static short *wtab, *wtab1, *wtabs;
  119.  
  120. static int fdate = FALSE, idir = 1, animate = FALSE;
  121. static long lincr = 3600;
  122. static long cctime;
  123.  
  124. /*  Forward procedures    */
  125.  
  126. double jtime(), gmst();
  127. void drawterm(), sunpos(), projillum(), moveterm(), outdiff();
  128.  
  129.  
  130. /*  PW_MODE: GEM-version */
  131. #define PIX_SRC     0x01
  132. #define PIX_DST     0x02
  133. #define PIX_NOT     ~
  134.  
  135. /* Used in pw_vector. Not complete! */
  136. void pw_setmode(pw_mode)
  137. int pw_mode;
  138. {
  139.     int gemmode = 1;
  140.     
  141.     switch (pw_mode) {
  142.     case PIX_SRC ^ PIX_DST:
  143.         gemmode = 3;
  144.         break;
  145.     }
  146.     vswr_mode(handle, gemmode);
  147. }
  148.  
  149. /* PW_VECTOR: draw a line using gem. Could draw directly to screen or
  150.               by a Aline for speed, but this is easier */
  151. void pw_vector(pw, x1, y1, x2, y2, mode, color)
  152. void    *pw;
  153. int     x1, x2, y1, y2, mode, color;
  154. {
  155.     pw_setmode(mode); 
  156.     vsl_color(handle, color);
  157.     pxyarray[0] = x1;
  158.     pxyarray[1] = y1;
  159.     pxyarray[2] = x2;
  160.     pxyarray[3] = y2;
  161.     v_pline(handle,2,pxyarray);
  162. }
  163.  
  164. /* PW_BATCH_ON/OFF: use define to avoid double define because of 
  165.                     8 chars limit */
  166. #define pw_batch_on pw_b_on
  167. void pw_b_on(pw)
  168. void    *pw;
  169. {
  170.     Scr2Init();
  171.     Scr2Copy();
  172. }
  173.  
  174. #define pw_batch_off pw_b_off
  175. void pw_b_off(pw)
  176. void    *pw;
  177. {
  178.     Scr2Swap();
  179.     Scr2Exit();
  180. }
  181.  
  182. /*  UPDIMAGE  --  Update current displayed image.  */
  183. static void updimage(istimer)
  184. int istimer;
  185. {
  186.     int i, xl;
  187.     struct tm *ct;
  188.     char tbuf[100];
  189.     double jt, sunra, sundec, sunrv, sunlong, gt;
  190.     struct tm lt;
  191.     static int lisec = 61;       /* Last iconic seconds */
  192.     static long lctime = 0;    /* Last full calculation time */
  193.     static  int *cpw;
  194.  
  195.     if (!istimer) {
  196.           xdots = OXDOTS;
  197.           ydots = OYDOTS;
  198.  
  199.           cpw = Logbase();
  200.           for (i=0 ; i < sizeof(bimg)/sizeof(int) ; i++)
  201.               cpw[i] = ~(bimg[i]);
  202.           for (; i < 16000 ; i++)
  203.               cpw[i] = 0xFFFF;
  204.     }
  205.  
  206.     /* If this is a full repaint of the window, force complete
  207.        recalculation. */
  208.  
  209.     if (!istimer) {
  210.        lctime = 0;
  211.        onoon = -1;
  212.        lisec = 61;
  213.        for (i = 0; i < OYDOTS; i++)
  214.           wtab1[i] = -1;
  215.     }
  216.  
  217.     if (fdate) {
  218.        if (animate)
  219.           cctime += lincr;
  220.        if (cctime < 0)
  221.           cctime = 0;
  222.     } else {
  223.        V time(&cctime);
  224.     }
  225.     lt = *localtime(&cctime);
  226.  
  227.     ct = gmtime(&cctime);
  228.  
  229.     jt = jtime(ct);
  230.     sunpos(jt, FALSE, &sunra, &sundec, &sunrv, &sunlong);
  231.     gt = gmst(jt);
  232.  
  233.     /* Projecting the illumination curve  for the current seasonal
  234.            instant is costly.  If we're running in real time, only  do
  235.        it every PROJINT seconds.  */
  236.  
  237.     if (fdate || !istimer || ((cctime - lctime) > PROJINT)) {
  238.        projillum(wtab, xdots, ydots, sundec);
  239.        wtabs = wtab;
  240.        wtab = wtab1;
  241.        wtab1 = wtabs;
  242.        lctime = cctime;
  243.     }
  244.  
  245.     sunlong = fixangle(180.0 + (sunra - (gt * 15)));
  246.     xl = sunlong * (xdots / 360.0);
  247.  
  248.     /* If the subsolar point has moved at least one pixel, update
  249.        the illuminated area on the screen.    */
  250.  
  251.     if (fdate || !istimer || (onoon != xl)) {
  252.        if (bufferio) 
  253.            pw_batch_on(0);
  254.        moveterm(wtab1, xl, wtab, onoon, xdots, ydots);
  255.        if (bufferio) 
  256.            pw_batch_off(0);
  257.        onoon = xl;
  258.     }
  259.  
  260.     /* Display time */
  261.     sprintf(tbuf, "\033p\033Y%c%c%02d:%02d:%02d %s %02d/%02d/%02d",
  262.             ' '+22, ' '+7,
  263.             lt.tm_hour, lt.tm_min, 2*lt.tm_sec,
  264.             wdname[lt.tm_wday],
  265.             lt.tm_mon + 1, lt.tm_mday, (lt.tm_year % 100));
  266.     puts(tbuf);
  267.  
  268.     /* Display mode */
  269.     sprintf(tbuf, "\033p\033Y%c%c(", ' '+23, ' '+7);
  270.     strcat(tbuf, (animate) ? "Animate" : "Real time" );
  271.     if (animate) {
  272.         strcat(tbuf, (idir < 0) ? ", <<" : ", >>");
  273.         switch (abs(lincr)) {
  274.         case 3600L:
  275.            strcat(tbuf, " hour");
  276.            break;
  277.         case 86400L:
  278.            strcat(tbuf, " day");
  279.            break;
  280.         case 604800L:
  281.            strcat(tbuf, " week");
  282.            break;
  283.         case 2592000L:
  284.            strcat(tbuf, " month");
  285.            break;
  286.         case 31536000L:
  287.            strcat(tbuf, " year");
  288.            break;
  289.         }
  290.     }
  291.     strcat(tbuf, ")");
  292.     puts(tbuf);
  293.  
  294.     /* Display credits */
  295.     printf("\033p\033Y%c%cSUN   : John Walker, Autodesk, Inc.", ' '+22, ' '+40);
  296.     printf("\033p\033Y%c%cATARI : Joep Mathijssen", ' '+23, ' '+40);
  297. }
  298.  
  299. /*  Frame event processor  
  300. static frame_event_proc(frame, event, arg, type)
  301. Frame frame;
  302. Event *event;
  303. Notify_arg arg;
  304. Notify_event_type type;
  305. {
  306.     switch (event_id(event)) {
  307.  
  308.        case WIN_REPAINT:
  309.           if (window_get(bf, FRAME_CLOSED)) {
  310.          updimage(FALSE);
  311.           } else {
  312.          xdots = OXDOTS;
  313.          ydots = OYDOTS;
  314.  
  315.          updimage(FALSE);
  316.           }
  317.           break;
  318.  
  319.        default:
  320.           window_default_event_func(frame, event, arg, type);
  321.           break;
  322.     }
  323. }*/
  324.  
  325.  
  326. /*  Timer notification procedure.  */
  327.  
  328. void timer_proc()
  329. {
  330.     updimage(TRUE);
  331. }
  332.  
  333.  
  334. /*  CEVENT  --    Canvas event handler  */
  335.  
  336. static void cevent()
  337. {
  338.     DialogSetItem( dialog_addr, FORWARD , (idir>0) );
  339.     DialogSetItem( dialog_addr, BACKWARD, (idir<0) );
  340.     DialogSetItem( dialog_addr, REALTIME, (!animate));
  341.     DialogSetItem( dialog_addr, ANIMATE , (animate));
  342.     DialogSetItem( dialog_addr, HOUR    , (animate && abs(lincr) == 3600L ));
  343.     DialogSetItem( dialog_addr, DAY     , (animate && abs(lincr) == 86400L ));
  344.     DialogSetItem( dialog_addr, WEEK    , (animate && abs(lincr) == 604800L ));
  345.     DialogSetItem( dialog_addr, MONTH   , (animate && abs(lincr) == 2592000L));
  346.     DialogSetItem( dialog_addr, YEAR    , (animate && abs(lincr) == 31536000L));
  347.     DialogSetItem( dialog_addr, BUFFER  , bufferio );
  348.  
  349.     switch (DialogDo( dialog_addr )) {
  350.     case FORWARD:       /* Forward */
  351.         if (idir < 0)
  352.             lincr = -lincr;
  353.         idir = 1;
  354.         break;
  355.  
  356.     case BACKWARD:       /* Backward */
  357.         if (idir > 0)
  358.            lincr = -lincr;
  359.         idir = -1;
  360.         break;
  361.  
  362.     case HOUR:       /* Hour */
  363.         cctime += (lincr = 3600L * idir);
  364.         fdate = TRUE;
  365.         break;
  366.  
  367.     case DAY:       /* Day */
  368.         cctime += (lincr = 86400L * idir);
  369.         fdate = TRUE;
  370.         break;
  371.  
  372.     case WEEK:       /* Week */
  373.         cctime += (lincr = 86400L * 7 * idir);
  374.         fdate = TRUE;
  375.         break;
  376.  
  377.     case MONTH:       /* Month */
  378.         cctime += (lincr = 86400L * 30 * idir);
  379.         fdate = TRUE;
  380.         break;
  381.  
  382.     case YEAR:       /* Year */
  383.         cctime += (lincr = 86400L * 365L * idir);
  384.         fdate = TRUE;
  385.         break;
  386.  
  387.     case ANIMATE:       /* Animate */
  388.         animate = fdate = TRUE;
  389.         /* V notify_set_itimer_func(bf, timer_proc, ITIMER_REAL,
  390.           &quick_timer, (struct itimerval *) NULL);*/
  391.         break;
  392.  
  393.     case REALTIME:       /* Real time */
  394.         animate = fdate = FALSE;
  395.         /*V notify_set_itimer_func(bf, timer_proc, ITIMER_REAL,
  396.           ¬if_timer, (struct itimerval *) NULL);*/
  397.         break;
  398.     }
  399.     bufferio = DialogGetItem( dialog_addr, BUFFER );
  400.  
  401.     updimage(FALSE);
  402. }
  403.  
  404. /*  MAIN  --  Main program  */
  405.  
  406. void main(argc, argv)
  407. int argc;
  408. char *argv[];
  409. {
  410.     int  ev_mwhich, dummy, ev_breturn, ev_bbutton;
  411.     bool eop;
  412.  
  413.     if (argc!=1)
  414.         GemAbort("USAGE: sunclock");
  415.  
  416.     GemInit(cHighRez, "sunclock.rsc");
  417.     dialog_addr = DialogInit( SUNCLOCK );
  418.     bufferio = TRUE;
  419.  
  420.     printf("\033f\033E");
  421.     v_hide_c(handle);
  422.  
  423.     xdots = OXDOTS;
  424.     ydots = OYDOTS;
  425.  
  426.     wtab = (short *) malloc((unsigned int) ydots * sizeof(short));
  427.     wtab1 = (short *) malloc((unsigned int) ydots * sizeof(short));
  428.  
  429.     updimage(FALSE);
  430.     eop = FALSE;
  431.     while (!eop) {
  432.         ev_mwhich = evnt_multi(MU_BUTTON|MU_TIMER,
  433.                                2,1,1,                        /* MU_BUTTON */
  434.                                0,0,0,0,0,0,0,0,0,0,          /* MU_M1/2   */
  435.                                0,                            /* MU_MESAG  */
  436.                                1000,0,                       /* MU_TIMER  */
  437.                                &dummy, &dummy,
  438.                                &ev_bbutton,
  439.                                &dummy, &dummy,
  440.                    &ev_breturn);
  441.         switch (ev_mwhich) {
  442.         case MU_BUTTON:
  443.             if (ev_breturn == 1)
  444.                 cevent();
  445.             else
  446.                 eop = TRUE;
  447.             break;
  448.         case MU_TIMER:
  449.             timer_proc();
  450.             break;
  451.         }
  452.     }
  453.  
  454.     puts("\033q\033E");
  455.     GemExit();
  456. }
  457.  
  458. /*  JDATE  --  Convert internal GMT date and time to Julian day
  459.            and fraction.  */
  460.  
  461. static long jdate(t)
  462. struct tm *t;
  463. {
  464.     long c, m, y;
  465.  
  466.     y = t->tm_year + 1900;
  467.     m = t->tm_mon + 1;
  468.     if (m > 2)
  469.        m = m - 3;
  470.     else {
  471.        m = m + 9;
  472.        y--;
  473.     }
  474.     c = y / 100L;           /* Compute century */
  475.     y -= 100L * c;
  476.     return t->tm_mday + (c * 146097L) / 4 + (y * 1461L) / 4 +
  477.         (m * 153L + 2) / 5 + 1721119L;
  478. }
  479.  
  480. /* JTIME --    Convert internal GMT  date  and    time  to  astronomical
  481.            Julian  time  (i.e.   Julian  date  plus  day fraction,
  482.            expressed as a double).    */
  483.  
  484. static double jtime(t)
  485. struct tm *t;
  486. {
  487.     return (jdate(t) - 0.5) + 
  488.        (((long) t->tm_sec) +
  489.          60L * (t->tm_min + 60L * t->tm_hour)) / 86400.0;
  490. }
  491.  
  492. /*  KEPLER  --    Solve the equation of Kepler.  */
  493. static double kepler(m, ecc)
  494. double m, ecc;
  495. {
  496.     double e, delta, cs;
  497.  
  498. #define EPSILON 1E-6
  499.  
  500.     e = m = dtr(m);
  501.     do {
  502.        delta = e - ecc * sin(e) - m;
  503.        cs = 1 - (ecc * cos(e));    /* Use 'cs' to avoid bug in TC v1.0 */
  504.        e -= delta / cs;
  505.     } while (abs(delta) > EPSILON);
  506.     return e;
  507. }
  508.  
  509. /*  SUNPOS  --    Calculate position of the Sun.    JD is the Julian  date
  510.         of  the  instant for which the position is desired and
  511.         APPARENT should be nonzero if  the  apparent  position
  512.         (corrected  for  nutation  and aberration) is desired.
  513.                 The Sun's co-ordinates are returned  in  RA  and  DEC,
  514.         both  specified  in degrees (divide RA by 15 to obtain
  515.         hours).  The radius vector to the Sun in  astronomical
  516.                 units  is returned in RV and the Sun's longitude (true
  517.         or apparent, as desired) is  returned  as  degrees  in
  518.         SLONG.    */
  519. static void sunpos(jd, apparent, ra, dec, rv, slong)
  520. double jd;
  521. int apparent;
  522. double *ra, *dec, *rv, *slong;
  523. {
  524.     double t, t2, t3, l, m, e, ea, v, theta, omega,
  525.            eps;
  526.  
  527.     /* Time, in Julian centuries of 36525 ephemeris days,
  528.        measured from the epoch 1900 January 0.5 ET. */
  529.  
  530.     t = (jd - 2415020.0) / 36525.0;
  531.     t2 = t * t;
  532.     t3 = t2 * t;
  533.  
  534.     /* Geometric mean longitude of the Sun, referred to the
  535.        mean equinox of the date. */
  536.  
  537.     l = fixangle(279.69668 + 36000.76892 * t + 0.0003025 * t2);
  538.  
  539.         /* Sun's mean anomaly. */
  540.  
  541.     m = fixangle(358.47583 + 35999.04975*t - 0.000150*t2 - 0.0000033*t3);
  542.  
  543.         /* Eccentricity of the Earth's orbit. */
  544.  
  545.     e = 0.01675104 - 0.0000418 * t - 0.000000126 * t2;
  546.  
  547.     /* Eccentric anomaly. */
  548.  
  549.     ea = kepler(m, e);
  550.  
  551.     /* True anomaly */
  552.  
  553.     v = fixangle(2 * rtd(atan(sqrt((1 + e) / (1 - e))  * tan(ea / 2))));
  554.  
  555.         /* Sun's true longitude. */
  556.  
  557.     theta = l + v - m;
  558.  
  559.     /* Obliquity of the ecliptic. */
  560.  
  561.     eps = 23.452294 - 0.0130125 * t - 0.00000164 * t2 + 0.000000503 * t3;
  562.  
  563.         /* Corrections for Sun's apparent longitude, if desired. */
  564.  
  565.     if (apparent) {
  566.        omega = fixangle(259.18 - 1934.142 * t);
  567.        theta = theta - 0.00569 - 0.00479 * sin(dtr(omega));
  568.        eps += 0.00256 * cos(dtr(omega));
  569.     }
  570.  
  571.         /* Return Sun's longitude and radius vector */
  572.  
  573.     *slong = theta;
  574.     *rv = (1.0000002 * (1 - e * e)) / (1 + e * cos(dtr(v)));
  575.  
  576.     /* Determine solar co-ordinates. */
  577.  
  578.     *ra= fixangle(rtd(atan2(cos(dtr(eps)) * sin(dtr(theta)), cos(dtr(theta)))));
  579.     *dec = rtd(asin(sin(dtr(eps)) * sin(dtr(theta))));
  580. }
  581.  
  582. /*  GMST  --  Calculate Greenwich Mean Siderial Time for a given
  583.           instant expressed as a Julian date and fraction.    */
  584.  
  585. static double gmst(jd)
  586. double jd;
  587. {
  588.     double t, theta0;
  589.  
  590.  
  591.     /* Time, in Julian centuries of 36525 ephemeris days,
  592.        measured from the epoch 1900 January 0.5 ET. */
  593.  
  594.     t = ((floor(jd + 0.5) - 0.5) - 2415020.0) / 36525.0;
  595.  
  596.     theta0 = 6.6460656 + 2400.051262 * t + 0.00002581 * t * t;
  597.  
  598.     t = (jd + 0.5) - (floor(jd + 0.5));
  599.  
  600.     theta0 += (t * 24.0) * 1.002737908;
  601.  
  602.     theta0 = (theta0 - 24.0 * (floor(theta0 / 24.0)));
  603.  
  604.     return theta0;
  605. }
  606.  
  607. /*  PROJILLUM  --  Project illuminated area on the map.  */
  608.  
  609. static void projillum(wtab, xdots, ydots, dec)
  610. short *wtab;
  611. int xdots, ydots;
  612. double dec;
  613. {
  614.     int i, ftf = TRUE, ilon, ilat, lilon, lilat, xt;
  615.     double m, x, y, z, th, lon, lat, s, c;
  616.  
  617.     /* Clear unoccupied cells in width table */
  618.  
  619.     for (i = 0; i < ydots; i++)
  620.        wtab[i] = -1;
  621.  
  622.     /* Build transformation for declination */
  623.  
  624.     s = sin(-dtr(dec));
  625.     c = cos(-dtr(dec));
  626.  
  627.     /* Increment over a semicircle of illumination */
  628.  
  629.     for (th = -(PI / 2); th <= PI / 2 + 0.001;
  630.          th += PI / TERMINC) {
  631.  
  632.        /* Transform the point through the declination rotation. */
  633.  
  634.        x = -s * sin(th);
  635.        y = cos(th);
  636.        z = c * sin(th);
  637.  
  638.        /* Transform the resulting co-ordinate through the
  639.           map projection to obtain screen co-ordinates. */
  640.  
  641.        lon = (y == 0 && x == 0) ? 0.0 : rtd(atan2(y, x));
  642.        lat = rtd(asin(z));
  643.  
  644.        ilat = ydots - (lat + 90) * (ydots / 180.0);
  645.        ilon = lon * (xdots / 360.0);
  646.  
  647.        if (ftf) {
  648.  
  649.           /* First time.  Just save start co-ordinate. */
  650.  
  651.           lilon = ilon;
  652.           lilat = ilat;
  653.           ftf = FALSE;
  654.        } else {
  655.  
  656.           /* Trace out the line and set the width table. */
  657.  
  658.           if (lilat == ilat) {
  659.          wtab[(ydots - 1) - ilat] = ilon == 0 ? 1 : ilon;
  660.           } else {
  661.          m = ((double) (ilon - lilon)) / (ilat - lilat);
  662.          for (i = lilat; i != ilat; i += sgn(ilat - lilat)) {
  663.             xt = lilon + floor((m * (i - lilat)) + 0.5);
  664.             wtab[(ydots - 1) - i] = xt == 0 ? 1 : xt;
  665.          }
  666.           }
  667.           lilon = ilon;
  668.           lilat = ilat;
  669.        }
  670.     }
  671.  
  672.     /* Now tweak the widths to generate full illumination for
  673.        the correct pole. */
  674.  
  675.     if (dec < 0.0) {
  676.        ilat = ydots - 1;
  677.        lilat = -1;
  678.     } else {
  679.        ilat = 0;
  680.        lilat = 1;
  681.     }
  682.  
  683.     for (i = ilat; i != ydots / 2; i += lilat) {
  684.        if (wtab[i] != -1) {
  685.           while (TRUE) {
  686.          wtab[i] = xdots / 2;
  687.          if (i == ilat)
  688.             break;
  689.          i -= lilat;
  690.           }
  691.           break;
  692.        }
  693.     }
  694. }
  695.  
  696. /*  XSPAN  --  Complement a span of pixels.  Called with line in which
  697.            pixels are contained, leftmost pixel in the  line,  and
  698.            the   number   of   pixels   to     complement.   Handles
  699.            wrap-around at the right edge of the screen.  */
  700.  
  701. static void xspan(pline, leftp, npix)
  702. int pline, leftp, npix;
  703. {
  704.     leftp = leftp % xdots;
  705.  
  706.     if ((leftp + npix) > xdots) {
  707.        V pw_vector(0, leftp, pline, xdots - 1, pline,
  708.          PIX_SRC ^ PIX_DST, 1);
  709.        V pw_vector(0, 0, pline, (leftp + npix) - (xdots + 1),
  710.          pline, PIX_SRC ^ PIX_DST, 1);
  711.     } else {
  712.        V pw_vector(0, leftp, pline, leftp + (npix - 1), pline,
  713.          PIX_SRC ^ PIX_DST, 1);
  714.     }
  715. }
  716.  
  717. /*  MOVETERM  --  Update illuminated portion of the globe.  */
  718.  
  719. static void moveterm(wtab, noon, otab, onoon, xdots, ydots)
  720. short *wtab, *otab;
  721. int noon, onoon, xdots, ydots;
  722. {
  723.     int i, ol, oh, nl, nh;
  724.  
  725.     for (i = 0; i < ydots; i++) {
  726.  
  727.        /* If line is off in new width table but is set in
  728.           the old table, clear it. */
  729.  
  730.        if (wtab[i] < 0) {
  731.           if (otab[i] >= 0) {
  732.          xspan(i, ((onoon - otab[i]) + xdots) % xdots,
  733.             otab[i] * 2);
  734.           }
  735.        } else {
  736.  
  737.           /* Line is on in new width table.  If it was off in
  738.          the old width table, just draw it. */
  739.  
  740.           if (otab[i] < 0) {
  741.          xspan(i, ((noon - wtab[i]) + xdots) % xdots,
  742.             wtab[i] * 2);
  743.           } else {
  744.  
  745.          /* If both the old and new spans were the entire
  746.                     screen, they're equivalent. */
  747.  
  748.          if ((otab[i] == wtab[i]) && (wtab[i] == (xdots / 2)))
  749.             continue;
  750.  
  751.          /* The line was on in both the old and new width
  752.             tables.  We must adjust the difference in the
  753.             span.  */
  754.  
  755.          ol =  ((onoon - otab[i]) + xdots) % xdots;
  756.          oh = (ol + otab[i] * 2) - 1;
  757.          nl =  ((noon - wtab[i]) + xdots) % xdots;
  758.          nh = (nl + wtab[i] * 2) - 1;
  759.  
  760.          /* If spans are disjoint, erase old span and set
  761.             new span. */
  762.  
  763.          if (oh < nl || nh < ol) {
  764.             xspan(i, ol, (oh - ol) + 1);
  765.             xspan(i, nl, (nh - nl) + 1);
  766.          } else {
  767.             /* Clear portion(s) of old span that extend
  768.                beyond end of new span. */
  769.             if (ol < nl) {
  770.                xspan(i, ol, nl - ol);
  771.                ol = nl;
  772.             }
  773.             if (oh > nh) {
  774.                xspan(i, nh + 1, oh - nh);
  775.                oh = nh;
  776.             }
  777.             /* Extend existing (possibly trimmed) span to
  778.                correct new length. */
  779.             if (nl < ol) {
  780.                xspan(i, nl, ol - nl);
  781.             }
  782.             if (nh > oh) {
  783.                xspan(i, oh + 1, nh - oh);
  784.             }
  785.          }
  786.           }
  787.        }
  788.        otab[i] = wtab[i];
  789.     }
  790. }
  791.